#pragma once

#include <Windows.h>
#include <vector>
#include <boost/functional/hash.hpp>
#include <boost/unordered_map.hpp>

#include "CallbackWnd.h"

class CUniqueIcon
{
public:
	CUniqueIcon(HICON hIcon, int iIconIndex)
	{
		m_hIcon = hIcon;
		m_iIconIndex = iIconIndex;
	}

	HICON m_hIcon;
	int m_iIconIndex;
};

class CUniqueProcessKey
{
public:
	CUniqueProcessKey(DWORD dwProcessId, FILETIME *createTime)
	{
		m_ProcessId = dwProcessId;
		m_CreateTime = *createTime;
	}
	bool operator==(const CUniqueProcessKey &key)const
	{
		if (key.m_ProcessId == this->m_ProcessId && key.m_CreateTime.dwLowDateTime == this->m_CreateTime.dwLowDateTime &&key.m_CreateTime.dwHighDateTime == this->m_CreateTime.dwHighDateTime)
			return true;

		return false;
	}
public:
	DWORD m_ProcessId;
	FILETIME m_CreateTime;
};

class CUniqueProcessHasher
{
public:
	std::size_t operator()(const CUniqueProcessKey& key) const
	{
		using boost::hash_value;
		using boost::hash_combine;
		// Start with a hash value of 0 .
		std::size_t seed = 0;
		// Return the result.
		boost::hash_combine(seed, hash_value(key.m_ProcessId));
		boost::hash_combine(seed, hash_value(key.m_CreateTime.dwHighDateTime));
		boost::hash_combine(seed, hash_value(key.m_CreateTime.dwLowDateTime));
		return seed;
	}
};

class CUniqueProcess;

typedef std::vector<CUniqueProcess *> CProcessList;
typedef boost::unordered_map<CUniqueProcessKey, CUniqueProcess *, CUniqueProcessHasher> CProcessKeyMap;
typedef boost::unordered_multimap<DWORD, CUniqueProcess *> CProcessIdMap;
typedef boost::unordered_map<std::wstring, CUniqueIcon *> CUniqueIconMap;

class CUniqueProcess
{
public:
	CUniqueProcess(DWORD dwProcessId, DWORD dwParentProcessId, FILETIME *createTime, bool bIs64Bit, DWORD dwSessionId, LPCWSTR szImagePath);
	bool operator==(const CUniqueProcess &key)const;
public:
	DWORD m_ProcessId;
	DWORD m_ParentProcessId;
	FILETIME m_CreateTime;
	DWORD m_SessionId;
	std::wstring m_DisplayName;//for wow64?
	std::wstring m_ProcessName;
	std::wstring m_ImagePath;
	CUniqueProcess *m_pParentProcess;
	CProcessList m_ChildProcesses;
	bool m_bAlive;
	bool m_bIs64Bit;

	PVOID m_TreeNode;
	CUniqueIcon *m_Icon;
};

class CProcessMgr
{
public:
	CProcessMgr();
	~CProcessMgr();
	void Lock();
	void Unlock();
	CUniqueProcess *Find(DWORD dwProcessId, FILETIME *CreateTime);
	CUniqueProcess *Find(DWORD dwProcessId);

	void InsertProcess(CUniqueProcess *up);
	void CallWndCallbacks(CUniqueProcess *up, UINT Msg);
	void FillParent(CUniqueProcess *up);
	void FillIcon(CUniqueProcess *up);
	//Initialization
	void FillList(void);
	void RegisterWndCallbacks(HWND hWnd);
public:
	CProcessList m_List;
	CProcessKeyMap m_KeyMap;
	CProcessIdMap m_IdMap;
	HANDLE m_hReadyEvent;
	CImageList m_IconList;
	CUniqueIconMap m_UniqueIconMap;
private:
	CRITICAL_SECTION m_Lock;
	CCallbackWnds m_CallbackWnds;
};

extern CProcessMgr m_ProcessMgr;

#define WM_ADDPROCESS WM_USER+100
#define WM_UNFRESHPROCESS WM_USER+101
#define WM_KILLPROCESS WM_USER+102
#define WM_REMOVEPROCESS WM_USER+103